package znet

import (
	"bytes"
	"encoding/binary"
	"errors"
	"fmt"
	"sync"
	"zinx-tianjing-study/ziface"
)

type DataPack struct{}

var instance *DataPack

func GetDataPack() *DataPack {
	var once sync.Once
	once.Do(func() {
		instance = &DataPack{}
	})
	return instance
}

func (d *DataPack) GetHeadLen() uint32 {
	//datalen + id
	return 8
}
func (d *DataPack) Pack(msg ziface.IMessage) ([]byte, error) {
	dataBuff := bytes.NewBuffer([]byte{})

	// 1. 写入数据长度（4字节大端序）
	if err := binary.Write(dataBuff, binary.BigEndian, msg.GetDataLen()); err != nil {
		return nil, fmt.Errorf("写入长度失败: %w", err)
	}

	// 2. 写入消息ID（4字节大端序）
	if err := binary.Write(dataBuff, binary.BigEndian, msg.GetMsgID()); err != nil {
		return nil, fmt.Errorf("写入消息ID失败: %w", err)
	}

	// 3. 校验数据长度一致性
	expectedLen := msg.GetDataLen()
	actualData := msg.GetData()
	if uint32(len(actualData)) != expectedLen {
		return nil, errors.New("声明长度与实际数据长度不符")
	}

	// 4. 写入消息实体
	if _, err := dataBuff.Write(actualData); err != nil {
		return nil, fmt.Errorf("写入消息体失败: %w", err)
	}

	return dataBuff.Bytes(), nil
}

var (
	ErrInvalidHeader  = errors.New("invalid header length")
	ErrDataCorruption = errors.New("data length mismatch")
	ErrExceedsMaxSize = errors.New("exceeds max packet size")
)

// 这里只能通过读取头部信息来进行获取数据，不然这里还是会出现粘包
func (d *DataPack) UnPack(data []byte) (ziface.IMessage, error) {

	// 1. 创建缓冲读取器并检查最小长度
	reader := bytes.NewReader(data)
	if reader.Len() < 8 { // 4字节DataLen + 4字节MsgID
		return nil, fmt.Errorf("%w: require 8 bytes, got %d",
			ErrInvalidHeader, reader.Len())
	}

	msg := &Message{}

	// 2. 大端序读取头部
	if err := binary.Read(reader, binary.BigEndian, &msg.DataLen); err != nil {
		return nil, fmt.Errorf("读取DataLen失败: %w", err)
	}
	if err := binary.Read(reader, binary.BigEndian, &msg.ID); err != nil {
		return nil, fmt.Errorf("读取MsgID失败: %w", err)
	}

	return msg, nil
}
